package com.mc13.gpslogger;
// Mobile Computing SS 13
// Gruppe 2 Challenge 2

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Vector;

import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

public class GPSActivity extends Activity implements LocationListener {
	private TextView statusField;
	private TextView loggingField;
	private ToggleButton toggleButton;
	private LocationManager locationManager;
	private String locationProvider;
	private List<GPSData> gpsDataList;
	private Button writeLog;
	private Button showLocation;
	private Button showGM;
	private ProgressBar progressBar; 
	String lastLat, lastLong;
	boolean isEnabled;
	Location lastLocation;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_gps);

		gpsDataList = new ArrayList<GPSData>();

		isEnabled = true;
		lastLat = "";
		lastLong = "";
		progressBar = (ProgressBar) findViewById(R.id.progressBar);
		statusField = (TextView) findViewById(R.id.statusField);
		loggingField = (TextView) findViewById(R.id.loggingField);
		toggleButton = (ToggleButton) findViewById(R.id.toggleGPSlogging);
		toggleButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				toggleEnabled();
			}
		});
		writeLog = (Button) findViewById(R.id.buttonWriteLog);
		writeLog.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View arg0) {
				writeLogfile();
			}
		});
		showLocation = (Button) findViewById(R.id.buttonShowLocation);
		showLocation.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View arg0) {
				openBrowserCurrentLocationAndPaths();
			}
		});
		showGM = (Button) findViewById(R.id.buttonShowGM);
		showGM.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View arg0) {
				openCurrentLocationGoogleMaps();
			}
		});

		locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

		Criteria criteria = new Criteria();
		criteria.setAccuracy(Criteria.ACCURACY_FINE); // we want GPS data

		locationProvider = locationManager.getBestProvider(criteria, false);
		lastLocation = locationManager
				.getLastKnownLocation(locationProvider);

		toggleButton.setChecked(isEnabled);

		if (lastLocation != null) {
			onLocationChanged(lastLocation);
		} else {
			loggingField.setText("Location not available");
		}
		updateStatusText();
	}

	@Override
	protected void onPause() {
		super.onPause();
		if (isEnabled) {
			locationManager.removeUpdates(this);
		}
	};

	@Override
	protected void onResume() {
		super.onResume();
		if (isEnabled) {
			locationManager.requestLocationUpdates(locationProvider, 500, 1,
					this);
		}
	};

	private void toggleEnabled() {
		if (isEnabled) {
			locationManager.removeUpdates(this);
			progressBar.setVisibility(View.INVISIBLE);
		} else {
			locationManager.requestLocationUpdates(locationProvider, 500, 1,
					this);
			progressBar.setVisibility(View.VISIBLE);
		}
		isEnabled = !isEnabled;
		toggleButton.setChecked(isEnabled);
		updateStatusText();
	}

	@Override
	public void onLocationChanged(Location location) {
		lastLocation = location;
		GPSData gpsData = new GPSData(location);
		
		gpsDataList.add(gpsData);

		loggingField.setText(gpsData.toLogField());
	}

	private void writeLogfile() {
		if (lastLocation == null) {
			Toast.makeText(this, "No location data yet ", Toast.LENGTH_SHORT)
					.show();
			return;
		}
		String state = Environment.getExternalStorageState();
		if (Environment.MEDIA_MOUNTED.equals(state)) {
			// we can write to the external storage
			String root = Environment.getExternalStorageDirectory().toString();
			File myDir = new File(root + "/gps_logs");
			myDir.mkdirs();
			String ts = String
					.valueOf(Calendar.getInstance().getTimeInMillis());
			String fname = "gpslog-" + ts + ".csv";
			File file = new File(myDir, fname);
			try {
				file.createNewFile();
				BufferedWriter buf = new BufferedWriter(new FileWriter(file,
						true));
				for (GPSData gpsData : gpsDataList) {
					buf.append(gpsData.toCSVrow());
					buf.newLine();
				}
				buf.newLine();
				buf.close();
				Toast.makeText(this, "Wrote /sdcard/gps_logs/" + fname,
						Toast.LENGTH_SHORT).show();
			} catch (Exception e) {
				Toast.makeText(this, e.toString(), Toast.LENGTH_SHORT).show();
			}
		} else {
			Toast.makeText(this, "External Storage unavailable ",
					Toast.LENGTH_SHORT).show();
		}
	}

	private void openBrowserCurrentLocationAndPaths() {
		// first let us build an interesting path
		// with significant location changes
		// strip the gps data which is similar to the previous
		GPSData lastGPSData = null;
		Vector <GPSData> interestingGPSDataList = new Vector<GPSData>();
		
		for (GPSData gpsData: gpsDataList) {
			if (lastGPSData == null) {
				// the first iteration
				lastGPSData = gpsData;
				interestingGPSDataList.add(gpsData);
				continue;
			}
			if (!gpsData.isCloseTo(lastGPSData, 0.005)) {
				// we moved a bit
				interestingGPSDataList.add(gpsData);
			}
			lastGPSData = gpsData;
		}
		
		if (interestingGPSDataList.size() < 1) {
			Toast.makeText(this, "No location data yet ", Toast.LENGTH_SHORT).show();	
			return;
		}
		
		int startIndex = interestingGPSDataList.size() - 5;
		if (startIndex < 0) startIndex = 0;
		String pipeSeperatedGpsPositions = "&path=";
		for (int i=startIndex; i < interestingGPSDataList.size(); ++i) {
			GPSData gpsData=interestingGPSDataList.get(i);
			pipeSeperatedGpsPositions += String.valueOf(gpsData.latitude) + "," + String.valueOf(gpsData.longitude);
			if (i != (interestingGPSDataList.size() -1)) 
				pipeSeperatedGpsPositions += "|";
		}
		if (interestingGPSDataList.size() <= 1) {
			// forget about it, no path with only 1 element...
			pipeSeperatedGpsPositions = "";
		}
		
		String lastPos = 
				String.valueOf(interestingGPSDataList.lastElement().latitude) + "," +
				String.valueOf(interestingGPSDataList.lastElement().longitude);
		
		String url = "http://maps.googleapis.com/maps/api/staticmap?size=400x400" +
				pipeSeperatedGpsPositions + 
				"&center=" + lastPos + 
				"&markers=" + lastPos + "&sensor=false";
		Intent browserIntent = new Intent(Intent.ACTION_VIEW,
					Uri.parse(url));
			startActivity(browserIntent);
	}
	
	private void openCurrentLocationGoogleMaps() {
		if (lastLocation == null) {
			Toast.makeText(this, "No location data yet ", Toast.LENGTH_SHORT)
					.show();
			return;
		}
		String uri = String.format(Locale.ENGLISH, "geo:%f,%f", lastLocation.getLatitude(), lastLocation.getLongitude());
		Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
		startActivity(intent);
	}
	
	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
		updateStatusText();
	}

	@Override
	public void onProviderEnabled(String provider) {
		updateStatusText();
	}

	@Override
	public void onProviderDisabled(String provider) {
		updateStatusText();
	}

	private boolean isGPSEnabled() {
		if (locationManager != null) {
			return locationManager
					.isProviderEnabled(LocationManager.GPS_PROVIDER);
		} else
			return false;
	}

	private void updateStatusText() {
		if (isEnabled) {
			boolean gpsEnabled = isGPSEnabled();
			if (gpsEnabled) {
				statusField.setText("GPS is available");
			} else {
				statusField.setText("GPS is disabled on your device");
			}
		} else {
			statusField.setText("Not running");
		}
	}
	//
	// @Override
	// public boolean onCreateOptionsMenu(Menu menu) {
	// // Inflate the menu; this adds items to the action bar if it is present.
	// getMenuInflater().inflate(R.menu.g, menu);
	// return true;
	// }
}
